{
	UCE - cross-platform game engine written in delphi.
	Copyright (c) 2009, Shutko Vitaly

	This file is part of UCE.

	UCE is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	UCE is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
}

unit uAppLinux;

interface

uses
  x, xlib, xutil, keysym, glx, uApp, uInp;

type
  TAppLinux = class(TApp)
  	disp: PDisplay;
    wnd: TWindow;
    attrs: array[0..10] of Integer;
    vi: PXVisualInfo;
    swa: TXSetWindowAttributes;

    atoms: record
      destroy, protocols: TAtom;
    end;

    function Init: Boolean; override;
    procedure PollEvents; override;

    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses
	uVar;

constructor TAppLinux.Create;
begin
	disp := nil;
  wnd := 0;
end;

destructor TAppLinux.Destroy;
begin
  if wnd <> 0 then XDestroyWindow(disp, wnd);
	if disp <> nil then XCloseDisplay(disp);
end;

function TAppLinux.Init: Boolean;
var
	scr: Integer;
  root: TWindow;
begin
  Result := False;

  disp := XOpenDisplay(nil);

  if disp = nil then
  begin
    //error
    Exit;
  end;

  scr := DefaultScreen(disp);

  attrs[0] := GLX_RGBA;
  attrs[1] := GLX_DOUBLEBUFFER;
  attrs[2] := None;

  vi := glXChooseVisual(disp, scr, @attrs[0]);

  if vi = nil then
  begin
    //error
    Exit;
  end;

  root := RootWindow(disp, vi.screen);

  FillChar(swa, SizeOf(swa), 0);

  swa.colormap   := XCreateColormap(disp, root, vi.visual, AllocNone);
  swa.event_mask := ExposureMask or ButtonPressMask or ButtonReleaseMask or
  	PointerMotionMask or KeyPressMask or KeyReleaseMask;

  wnd := XCreateWindow(disp, root, 0, 0, eng.conf.w, eng.conf.h, 0, vi.depth,
  	InputOutput, vi.visual, CWColormap or CWEventMask or CWX or CWY or
   	CWBackPixel or CWBorderPixel{ or CWOverrideRedirect}, @swa);

  if wnd = 0 then
  begin
    //error
    Exit;
  end;

  XStoreName(disp, wnd, PChar(eng.conf.title));

  atoms.destroy := XInternAtom(disp, 'WM_DELETE_WINDOW', True);
  atoms.protocols := XInternAtom(disp, 'WM_PROTOCOLS', True);

  XSetWMProtocols(disp, wnd, @atoms.destroy, 1);

  XMapRaised(disp, wnd);

  Result := True;
end;

function XKeyToScancode(xkey: PXKeyEvent): Integer;
var
	key: Integer;
begin
  key := XLookupKeysym(xkey, 0);

	case key of
		XK_Escape: Result := KEY_ESCAPE;
    XK_Tab: Result := KEY_TAB;
    XK_BackSpace: Result := KEY_BACKSPACE;
    XK_Space: Result := KEY_SPACE;
		XK_Return: Result := KEY_ENTER;
    XK_Shift_L, XK_Shift_R: Result := KEY_SHIFT;
    XK_Control_L, XK_Control_R: Result := KEY_CONTROL;
    XK_Alt_L, XK_Alt_R: Result := KEY_ALT;
		XK_Up: Result := KEY_UP;
		XK_Down: Result := KEY_DOWN;
		XK_Left: Result := KEY_LEFT;
		XK_Right: Result := KEY_RIGHT;
    else
    begin
      if (key >= XKc_A) and (key <= XKc_Z) then Result := KEY_A + key - XKc_A;
			if (key >= XK_A) and (key <= XK_Z) then Result := KEY_A + key - XK_A;
    end;
	end;
end;

procedure HandleEvent(event: PXEvent);
begin
  case event._type of
  	KeyPress: inp.keys[XKeyToScancode(@event.xkey)] := True;
    KeyRelease: inp.keys[XKeyToScancode(@event.xkey)] := False;
    ClientMessage:
    begin
    	if (event.xclient.message_type = TAppLinux(app).atoms.protocols) and
     		(event.xclient.data.l[0] = TAppLinux(app).atoms.destroy) then eng.looping := False;
    end;
  end;
end;

procedure TAppLinux.PollEvents;
var
	event: TXEvent;
begin
  while XPending(disp) <> 0 do
  begin
    XNextEvent(disp, @event);
    HandleEvent(@event);
  end;
end;

end.
